import json
import re

from django import http
from django.contrib.auth import authenticate, login
from django.contrib.auth import logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseForbidden
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection
from itsdangerous import BadData
from pymysql import DatabaseError
from weibo import APIClient

from apps.carts.until import merge_cart_cookie_to_redis
from apps.goods import models
from apps.goods.models import SKU
from apps.users.models import User, Address, OAuthSinaUser
from meiduo_mall import settings
from meiduo_mall.settings.dev import logger
from utils.response_code import RETCODE


class bangding1(View):
    def post(self, request):
        dict = json.loads(request.body.decode())
        mobile = dict.get('mobile')
        password = dict.get('password')
        sms_code = dict.get('sms_code')
        uid = dict.get('uid')
        # if not request.user.mobile == mobile:
        #     return http.HttpResponseForbidden('手机号不存在')
        if not uid:
            render(request, 'sina_callback.html', {'uid_errmsg': '无效的uid'})
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            user = User.objects.create_user(username=mobile, password=password, mobile=mobile)
        else:
            if not user.check_password(password):
                return render(request, 'sina_callback.html', {'account_errmsg': '用户名或者密码错误'})
        OAuthSinaUser.objects.create(uid=uid, user=user)
        login(request, user)
        response = JsonResponse({'status': 5000})
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)
        return response


class bangding(View):
    def get(self, request):
        code = request.GET.get('code')
        print(code)
        client = APIClient(
            # app_key： app_key值
            app_key=settings.dev.APP_KEY,
            # app_secret：app_secret 值
            app_secret=settings.dev.APP_SECRET,
            # redirect_uri ： 回调地址
            redirect_uri=settings.dev.REDIRECT_URL
        )
        code = request.GET.get('code')
        print(code)
        result = client.request_access_token(code)
        access_token = result.access_token
        uid = result.uid
        try:
            sina_user = OAuthSinaUser.objects.get(uid=uid)
        except OAuthSinaUser.DoesNotExist:
            # 不存在--绑定页面(sina_callback.html)--带着uid
            uid = uid
            return render(request, 'sina_callback.html', context={'uid': uid})
        user = sina_user.user
        response = redirect(reverse('contents:index'))
        response.set_cookie('username', user.username, max_age=24 * 14 * 3600)
        return response


class weibologin(View):
    def get(self, request):
        # APP_KEY = '3305669385'
        # APP_SECRET = '74c7bea69d5fc64f5c3b80c802325276'
        # REDIRECT_URL = 'http://www.meiduo.site:8000/sina_callback'
        next = request.GET.get('next')
        client = APIClient(
            # app_key： app_key值
            app_key=settings.dev.APP_KEY,
            # app_secret：app_secret 值
            app_secret=settings.dev.APP_SECRET,
            # redirect_uri ： 回调地址
            redirect_uri=settings.dev.REDIRECT_URL
        )
        login_url = client.get_authorize_url()
        return http.JsonResponse(
            {
                "code": 0,
                "errmsg": '提示信息',
                "login_url": login_url
            })


class UserBrowseHistory(LoginRequiredMixin, View):
    #     1.接受json参数
    def post(self, request):
        '''1.接受接送参数 2. 根据sku_id查询sku
        3.如果没有sku 保存到redis'''
        sku_id = json.loads(request.body.decode()).get('sku_id')
        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return HttpResponseForbidden('商品不存在!')
        history_redis_client = get_redis_connection('history')
        history_key = 'history_%s' % request.user.id
        redis_pipeline = history_redis_client.pipeline()
        # 3.1 去重
        history_redis_client.lrem(history_key, 0, sku_id)
        # 3.2 存储
        history_redis_client.lpush(history_key, sku_id)
        # 3.3 截取 5个
        history_redis_client.ltrim(history_key, 0, 4)
        redis_pipeline.execute()

        # 响应结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = models.SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})


# 新增收货地pip址
class CreateAddressView(LoginRequiredMixin, View):
    def post(self, request):
        # 1. 检验地址栏不能超过20个
        count = request.user.addresses.count()
        if count >= 20:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
        # 2.接收传过来的json二进制内容
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 3.教研参数是否存在和正确
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email

            )
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})


# 展示收货地址
class AddressView(LoginRequiredMixin, View):
    """用户收货地址"""

    def get(self, request):
        """提供收货地址界面"""
        login_user = request.user
        addresses = Address.objects.filter(user=login_user, is_deleted=False)
        addresses_dict_list = []
        for address in addresses:
            address_dict = {
                'id': address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            addresses_dict_list.append(address_dict)
        context = {'default_address_id': login_user.default_address_id,
                   'addresses': addresses_dict_list, }

        return render(request, 'user_center_site.html', context)


class VerifyEmailView(View):
    """验证邮箱"""

    def get(self, request):
        """实现邮箱验证逻辑"""
        # 接收参数
        token = request.GET.get('token')

        # 校验参数：判断token是否为空和过期，提取user
        if not token:
            return http.HttpResponseBadRequest('缺少token')

        user = check_verify_email_token(token)
        if not user:
            return http.HttpResponseForbidden('无效的token')

        # 修改email_active的值为True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')

        # 返回邮箱验证结果
        return redirect(reverse('users:info'))


# 验证连接提取用户信息
def check_verify_email_token(token):
    """
    验证token并提取user
    :param token: 用户信息签名后的结果
    :return: user, None
    """
    from utils.scert import SecretOauth
    try:
        token_dict = SecretOauth().loads(token)
    except BadData:
        return None

    try:
        user = User.objects.get(id=token_dict['user_id'], email=token_dict['email'])
    except Exception as e:
        logger.error(e)
        return None
    else:
        return user


class EmailView(LoginRequiredMixin, View):
    # 添加邮箱
    def put(self, request):

        json_str = request.body.decode()
        json_dict = json.loads(json_str)
        email = json_dict.get('email')
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('参数eamil错误')
        try:
            request.user.email = email
            print(request.user)
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})
        # return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})

        from celery_tasks.email.tasks import send_verify_email
        from apps.users.utils import generate_verify_email_url
        verify_url = generate_verify_email_url(request.user)
        send_verify_email.delay(email, verify_url)
        print('hhhdfdfgdgfdf')

        # 响应添加邮箱结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})


# 判断用户是否登陆
# 展示用户等路面
class UserInfoView(LoginRequiredMixin, View):
    # 用户中心
    def get(self, request):
        context = {'username': request.user.username,
                   'mobile': request.user.mobile,
                   'email': request.user.email,
                   'email_active': request.user.email_active}
        return render(request, 'user_center_info.html', context=context)


# 用户退出
class LogoutView(View):
    # 用户退出
    # 退出登陆时的核心思想时qingli登陆是的缓存的状态保持信息
    def get(self, request):
        logout(request)
        response = redirect(reverse('contents:index'))
        response.delete_cookie('username')
        return response


# 用户登录


class LoginView(View):
    def get(self, request):
        # response = merge_cart_cookie_to_redis(request=request, response=response)
        return render(request, 'login.html')

    def post(self, request):
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')
        if not all([username, password]):
            return http.HttpResponseForbidden('参数不齐全')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')

        # 验证用户名和密码用django自带的认证
        # from django.contrib.auth import authenticate
        # login 保持登陆状态  request.session.set_expiry()设置时间None代表默认值
        # from django.contrib.auth import authenticate, login
        user = authenticate(request, username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})
        login(request, user)
        if remembered != 'on':
            request.session.set_expiry(None)
        else:
            request.session.set_expiry(0)
        # response = merge_cart_cookie_to_redis(request, user, response)
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))
        response1 = merge_cart_cookie_to_redis(request, user, response)
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)
        return response


# 检验电话号码
class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': 'Ok', 'errmsg': 'OK', 'count': count})


# 校验用户名
class UsernameCountView(View):
    def get(selfself, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': 'OK', 'errmsg': 'OK', 'count': count})


# 注册用户
class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):

        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('请输入5-20个字符的用户名')
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选用户协议')
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except DatabaseError:
            return render(request, 'register.html', {'register_errmsg': '注册失败'})

        # 响应注册结果
        login(request, user)
        return redirect(reverse('contents:index'))
